package com.gitee.blane;

/*
 * Copyright 2001-2005 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.gitee.blane.util.EPlatform;
import com.gitee.blane.util.OSinfo;
import org.apache.maven.model.Build;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Execute;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;

import java.io.*;
import java.nio.file.Files;
import java.util.Map;
import java.util.Set;

/**
 *
 */
@Execute(goal = "deal")
@Mojo(name = "deal", defaultPhase = LifecyclePhase.PACKAGE)
public class BuildMojo extends AbstractMojo {

    @Parameter(defaultValue = "${project}", readonly = true, required = true)
    MavenProject project;


    @Parameter(defaultValue = "true")
    Boolean skipBuild;

    /**
     * build的构建参数. 其中jarFile 是默认的构建参数
     */
    @Parameter
    Map<String, String> buildArgs;

    /**
     * 需要移动到构建目录的资源
     */
    @Parameter
    Set<String> includes;

    @Parameter(defaultValue = "true")
    Boolean skipRun;

    @Parameter
    Map<String, String> runArgs;

    @Parameter(defaultValue = "true")
    Boolean skipPush;

    @Parameter
    String registry;

    @Parameter
    String password;

    @Parameter
    String username;


    @Parameter(defaultValue = "${project.name}:${project.version}")
    String imageName;


    String imageTag;


    Build build;

    @Override
    public void execute() throws MojoExecutionException {
        try {
            getLog().info("----------------初始化参数 ---------------");
            //初始化数据
            initParam();
            getLog().info("----------------创建docker构建目录target/docker---------------");
            //创建构建目录
            createDockerDir();
            getLog().info("----------------移动jar包---------------");
            //复制jar包
            copyJarFile();
            getLog().info("----------------移动Dockerfile文件---------------");
            //复制dockerFile
            copyDockerfile();
            getLog().info("----------------移动自定义资源文件---------------");
            //复制用户自定义的资源
            if (includes != null && !includes.isEmpty()) {
                copyResources();
            }
            //构建命令脚本
            getLog().info("---------------- 生成docker-build.sh脚本 ---------------");
            createBuildShell();
            getLog().info("---------------- 生成docker-run.sh脚本 ---------------");
            createRunShell();
            getLog().info("---------------- 生成docker-push.sh脚本 ---------------");
            createPushShell();


            if (!skipBuild) {
                getLog().info("---------------- 运行docker-build.sh脚本 ---------------");
                runShell("docker-build.sh");
            }
            if (!skipRun) {
                getLog().info("---------------- 运行docker-run.sh脚本 ---------------");
                runShell("docker-run.sh");
            }
            if (!skipPush) {
                getLog().info("---------------- 运行docker-push.sh脚本 ---------------");
                runShell("docker-push.sh");
            }
        } catch (Exception e) {
            getLog().error(e);
        }
    }

    private void initParam() {
        build = project.getBuild();
        if (imageName.contains(":")) {
            if (imageTag == null) {
                int i = imageName.lastIndexOf(":");
                String substring = imageName.substring(0, i);
                imageTag = imageName.substring(i + 1);
                imageName = substring;
            } else {
                imageName = imageName.replaceAll(":", "");
            }
        } else if (imageTag == null) {
            imageTag = project.getVersion();
        }
    }


    private File createDockerDir() {
        File dockerDir = new File(build.getDirectory() + "/docker");
        if (!dockerDir.exists() && !dockerDir.isDirectory()) {
            dockerDir.mkdirs();
        }
        return dockerDir;
    }

    private void copyDockerfile() throws IOException {
        File dockerFileSource = new File(project.getBasedir().getAbsolutePath() + "/Dockerfile");
        File dockerFileTarget = new File(build.getDirectory() + "/docker/Dockerfile");
        if (dockerFileTarget.exists()) {
            dockerFileTarget.delete();
        }

        Files.copy(dockerFileSource.toPath(), dockerFileTarget.toPath());

    }

    private void copyJarFile() throws IOException {
        File jarFileSource = new File(build.getDirectory() + "/" + build.getFinalName() + ".jar");
        File jarFileTarge = new File(build.getDirectory() + "/docker/" + build.getFinalName() + ".jar");
        if (!jarFileSource.exists()) {
            throw new RuntimeException(jarFileSource.getAbsolutePath() +
                    "中找不到jar包， 请使用<jarFile>传入jar的名称");
        }
        if (jarFileTarge.exists()) {
            jarFileTarge.delete();
        }
        Files.copy(jarFileSource.toPath(), jarFileTarge.toPath());

    }

    private void copyResources() throws IOException {
        for (String resouce : includes) {
            File source = new File(project.getBasedir().getAbsolutePath() + "/" + resouce);
            if (source.exists()) {
                File target = new File(build.getDirectory() + "/docker/" + source.getName());
                if (target.exists()) {
                    target.delete();
                }
                Files.copy(source.toPath(), target.toPath());
            } else {
                getLog().warn("-----  " + source.getAbsolutePath() + " 不存在, 移动失败");
            }
        }
    }

    private void createRunShell() throws IOException {
        StringBuilder shellStringBuilder = new StringBuilder();
        shellStringBuilder.append(System.lineSeparator());

        String tag = imageName + ":" + imageTag;

        shellStringBuilder.append("docker run ");
        shellStringBuilder.append(" -d ");
        shellStringBuilder.append(" --name " + imageName + "-" + imageTag);
        String port = buildArgs.get("port") == null ? buildArgs.get("PORT") : buildArgs.get("port");
        boolean runArgsExist = runArgs != null && !runArgs.isEmpty();
        if (runArgsExist) {
            Set<Map.Entry<String, String>> entries = runArgs.entrySet();
            for (Map.Entry<String, String> entry : entries) {
                shellStringBuilder.append(entry.getKey() + " " + entry.getValue() + " ");
            }
            boolean containPublishKey = runArgs.containsKey("-p") || runArgs.containsKey("--publish");
            if (!containPublishKey && port != null) {
                shellStringBuilder.append(" -p " + port + ":" + port + " ");
            }
        } else if (port != null) {
            shellStringBuilder.append(" -p " + port + ":" + port + " ");
        }

        shellStringBuilder.append(tag);
        shellStringBuilder.append(System.lineSeparator());
        File file = new File(build.getDirectory() + "/docker/docker-run.sh");
        try (FileWriter fileWriter = new FileWriter(file)) {
            fileWriter.write(shellStringBuilder.toString());
        }
    }


    private void createPushShell() throws IOException {
        StringBuilder shellStringBuilder = new StringBuilder();
        shellStringBuilder.append(System.lineSeparator());

        String tag;
        if (registry == null || "".equals(registry)) {
            tag = imageName + ":" + imageTag;
            //TODO 不进行打标签
        } else {
            tag = registry + ":" + imageName + "-" + imageTag;
            //打标签
            shellStringBuilder.append("docker tag ");
            shellStringBuilder.append(imageName + ":" + imageTag + " ");
            shellStringBuilder.append(tag);
            shellStringBuilder.append(System.lineSeparator());
            //登录服务
            shellStringBuilder.append("spawn  docker login --username=");
            shellStringBuilder.append(username + " " + registry);
            shellStringBuilder.append(System.lineSeparator());
            //输入密码
            shellStringBuilder.append("expect \"Password\" send \"");
            shellStringBuilder.append(password + "\\n\"");
            shellStringBuilder.append(System.lineSeparator());
        }
        //推送
        shellStringBuilder.append("docker push ");
        shellStringBuilder.append(tag);
        shellStringBuilder.append(System.lineSeparator());
        File file = new File(build.getDirectory() + "/docker/docker-push.sh");
        try (FileWriter fileWriter = new FileWriter(file)) {
            fileWriter.write(shellStringBuilder.toString());
        }
    }

    private void createBuildShell() throws IOException {
        StringBuilder shellStringBuilder = new StringBuilder();
        shellStringBuilder.append(System.lineSeparator());

        shellStringBuilder.append("docker stop $(docker ps -a | grep \"" + imageName + "\" | awk '{print $1 }')");
        shellStringBuilder.append(System.lineSeparator());
        shellStringBuilder.append("docker rm $(docker ps -a | grep \"" + imageName + "\" | awk '{print $1 }')");
        shellStringBuilder.append(System.lineSeparator());
        shellStringBuilder.append("docker rmi $(docker images | grep \"" + imageName + "\" | awk '{print $3}')");
        shellStringBuilder.append(System.lineSeparator());

        shellStringBuilder.append(" docker build ");
        //--build-arg user=what_use
        if (buildArgs != null && !buildArgs.isEmpty()) {
            Set<Map.Entry<String, String>> entries = buildArgs.entrySet();

            for (Map.Entry<String, String> entry : entries) {
                String value = entry.getValue();
                shellStringBuilder.append(" --build-arg ");
                shellStringBuilder.append(entry.getKey() + "=" + value + " ");
            }
        }
        shellStringBuilder.append(" --build-arg ");
        shellStringBuilder.append("JAR_FILE=" + build.getFinalName() + ".jar ");

        shellStringBuilder.append(" -t ");
        shellStringBuilder.append(imageName);
        shellStringBuilder.append(":");
        shellStringBuilder.append(imageTag);
        shellStringBuilder.append(" . ");
        shellStringBuilder.append(System.lineSeparator());

        File file = new File(build.getDirectory() + "/docker/docker-build.sh");
        try (FileWriter fileWriter = new FileWriter(file)) {
            fileWriter.write(shellStringBuilder.toString());
        }
    }

    private boolean runShell(String shellName) throws IOException, InterruptedException {
        EPlatform oSname = OSinfo.getOSname();
        if (oSname == EPlatform.Windows) {
            getLog().warn("**************  windows系统, 本插件不支持运行构建命令 *************");
        }
        ProcessBuilder processBuilder = new ProcessBuilder();
        processBuilder.directory(new File(build.getDirectory() + "/docker"));
        processBuilder.redirectErrorStream(true);

        processBuilder.command("sh", shellName);

        Process start = processBuilder.start();
        InputStream inputStream = start.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String line;
        while ((line = bufferedReader.readLine()) != null ) {
            getLog().info(line);
        }
        if (start.waitFor() != 0) {
            return false;
        }
        return true;
    }


}
